/*
 * 文件名： WechatScanPayManager.java
 * 
 * 工程名称: bis-manager
 *
 * Gopay
 *
 * 创建日期： 2016年8月5日
 *
 * Copyright(C) 2016, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.manager.bank.scan;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.wechat.scan.req.ScanOrderQueryReqMsg;
import com.gopay.common.domain.bank.wechat.scan.req.ScanPayReqMsg;
import com.gopay.common.domain.bank.wechat.scan.req.ScanRefundQueryReqMsg;
import com.gopay.common.domain.bank.wechat.scan.req.ScanRefundReqMsg;
import com.gopay.common.domain.bank.wechat.scan.res.ScanOrderQueryResMsg;
import com.gopay.common.domain.bank.wechat.scan.res.ScanPayResultMsg;
import com.gopay.common.domain.bank.wechat.scan.res.ScanRefundQueryResMsg;
import com.gopay.common.domain.bank.wechat.scan.res.ScanRefundResMsg;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.businesses.ScanPayService;
import com.ibm.icu.util.Calendar;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.DomDriver;

/**
 * 微信扫码业务报文拼装处理
 *
 * @author 宣广海
 *
 * @version 
 *
 * @since 2016年8月5日
 */
public class WechatScanPayManager {
    
    private static Logger logger = LoggerFactory.getLogger(WechatScanPayManager.class);
	
	/**
	 * 注入对象
	 */
    @Resource(name = "wechatScanPayConfig")
    private Map<String,String> wechatScanPayConfig;
    
	@Resource(name = "wechatScanPayServiceClient")
	private ScanPayService wechatScanPayServiceClient;
	private static long seed = 0;

    
    public Object sign(BaseMessage msg) throws GopayException {
        ScanPayResultMsg resMessage = new ScanPayResultMsg();
        try {            
            msg.setBankOrderId(modifyOrderId(msg.getOrderId(),msg.getBankIntrChann().value));  
            ScanPayReqMsg message =(ScanPayReqMsg)msg;
            message.setService(wechatScanPayConfig.get("WECHATSCAN.PAY.SEVICE"));
            message.setVersion(wechatScanPayConfig.get("WECHATSCAN.PAY.VERSION"));
            message.setCharset(wechatScanPayConfig.get("WECHATSCAN.PAY.CHARSET"));
            message.setSign_type(wechatScanPayConfig.get("WECHATSCAN.PAY.SIGN.TYPE"));
            message.setMch_id(message.getMerID()); 
            message.setCustomerID("");
            message.setOut_trade_no(message.getBankOrderId());
            message.setDevice_info(message.getDeviceInfo());
            message.setBody(message.getGoodsBody());
            message.setLimit_credit_pay(message.getLimitCreditPay());
            message.setAttach("");
            message.setTotal_fee(format(message.getAmount().multiply(new BigDecimal(100))));//
            message.setMch_create_ip(message.getMchCreateIp());
            message.setNotify_url(message.getPayRuturnUrl());
            message.setTime_start(DateUtils.format(new Date()));
            message.setTime_expire(DateUtils.format(DateUtils.add(DateUtils.strToDate(message.getTime_start()), Calendar.MINUTE, 6)));
            message.setOp_user_id("");
            message.setGoods_tag(message.getGoodsTag());
            message.setProduct_id("");
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));            
            BankLogUtils.printWeChatManagerSignSendLog(message);
            resMessage=(ScanPayResultMsg) wechatScanPayServiceClient.payment(message);
            logger.info("WECHAT scan manager sign return message :"+ToStringBuilder.reflectionToString(resMessage));
        } catch (Exception e) {
        	logger.info(e.getMessage());
            throw new GopayException("扫码支付签名失败",e);
        }
        return resMessage;
    }

  
    public Object verify(BaseMessage msg) throws GopayException {
        boolean falg = false;
        BankLogUtils.printWeChatManagerVerifySendLog(msg);
        falg=(boolean) wechatScanPayServiceClient.verify(msg);
        BankLogUtils.printWeChatManagerVerifyReturnLog(msg,falg);
        return falg;
    }
    
    public Object orderQuery(BaseMessage obj) throws GopayException {      
        ScanOrderQueryResMsg resMsg =new ScanOrderQueryResMsg();
        try {
            ScanOrderQueryReqMsg message =(ScanOrderQueryReqMsg) obj;
            message.setService(wechatScanPayConfig.get("WECHATSCAN.ORDERQUERY.SEVICE"));
            message.setVersion(wechatScanPayConfig.get("WECHATSCAN.ORDERQUERY.VERSION"));
            message.setCharset(wechatScanPayConfig.get("WECHATSCAN.ORDERQUERY.CHARSET"));
            message.setSign_type(wechatScanPayConfig.get("WECHATSCAN.ORDERQUERY.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            message.setOut_trade_no(message.getBankOrderId());
            message.setNonce_str(creatSerialNumber(20));//随机字符串
            message.setPlainMessage(buildSignPlain(message));
            BankLogUtils.printWetChatManagerQuerySendLog(message);
            resMsg =(ScanOrderQueryResMsg) wechatScanPayServiceClient.queryOrder(message);
            logger.info("WECHAT scan manager query return message :"+ToStringBuilder.reflectionToString(resMsg));
        } catch (Exception e) {            
        	logger.info(e.getMessage());
            throw new GopayException("扫码支付订单查询失败",e);
        }
        return resMsg;
    }

   
    public Object refund(BaseMessage obj) throws GopayException {
        ScanRefundResMsg resMsg =new ScanRefundResMsg();
        try{
            ScanRefundReqMsg message =(ScanRefundReqMsg) obj;
            message.setService(wechatScanPayConfig.get("WECHATSCAN.REFUND.SEVICE"));
            message.setVersion(wechatScanPayConfig.get("WECHATSCAN.REFUND.VERSION"));
            message.setCharset(wechatScanPayConfig.get("WECHATSCAN.REFUND.CHARSET"));
            message.setSign_type(wechatScanPayConfig.get("WECHATSCAN.REFUND.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            /**
             * 原交易上送银行订单号
             */
            message.setOut_trade_no(message.getTkOriBankOrderId());
            /**
             * 退款订单号
             */
            message.setOut_refund_no(message.getBankOrderId());
            message.setTotal_fee(format(message.getTkOriAmount().multiply(new BigDecimal(100))));
            message.setRefund_fee(format(message.getAmount().multiply(new BigDecimal(100))));
            message.setOp_user_id(message.getMerID());
 //           message.setRefund_channel("ORIGINAL");
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));
            
            message.setRefundUrl(wechatScanPayConfig.get("WECHATSCAN.REFUND.URL"));
            logger.info("WECHAT scan manager refund send message:"+ToStringBuilder.reflectionToString(message));
            resMsg =(ScanRefundResMsg) wechatScanPayServiceClient.refund(message);
            logger.info("WECHAT scan manager refund return message:"+ToStringBuilder.reflectionToString(resMsg));
        } catch (Exception e){
        	logger.info(e.getMessage());
            throw new GopayException("威富通退款失败",e);
        }
        return resMsg;
    }


    public Object refundQuery(BaseMessage obj) throws GopayException {
        ScanRefundQueryResMsg resMsg =new ScanRefundQueryResMsg();
        try{
            ScanRefundQueryReqMsg message =(ScanRefundQueryReqMsg) obj;
            message.setService(wechatScanPayConfig.get("WECHATSCAN.REFUNDQUERY.SEVICE"));
            message.setVersion(wechatScanPayConfig.get("WECHATSCAN.REFUNDQUERY.VERSION"));
            message.setCharset(wechatScanPayConfig.get("WECHATSCAN.REFUNDQUERY.CHARSET"));
            message.setSign_type(wechatScanPayConfig.get("WECHATSCAN.REFUNDQUERY.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            message.setOut_trade_no(message.getTkOriBankOrderId());
            message.setTransaction_id("");
            /**
             * 商户退款单号
             */
            message.setOut_refund_no(message.getBankOrderId());
            message.setRefund_id("");
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));
            /**
             * 退款订单查询
             */
            message.setRefundQueryUrl(wechatScanPayConfig.get("WECHATSCAN.REFUNDQUERY.URL"));
            logger.info("WECHAT scan manager refundQuery send message:"+ToStringBuilder.reflectionToString(message));
            resMsg=(ScanRefundQueryResMsg) wechatScanPayServiceClient.refundQuery(message);
            logger.info("WECHAT scan manager refundQuery return message:"+ToStringBuilder.reflectionToString(resMsg));            
        } catch(Exception e){
        	logger.info(e.getMessage());
            throw new GopayException("威富通退款查询失败",e);
        }
        return resMsg;
    }

    

    /**
     * @Description: 生成随机字符串
     * @param length
     * @return
     * @author w_jiqing
     */
    public static String creatSerialNumber(int length) {
        byte[] randomSerial = new byte[length];
        String charactors = "123456789abcdefghigklmnopkrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
        int charSetLength = charactors.length();
        seed = seed ^ System.currentTimeMillis();
        java.util.Random randomNumber = new java.util.Random(seed);

        for (int i = 0; i < length; i++) {
            randomNumber.setSeed(seed);
            int j = (int) (randomNumber.nextFloat() * charSetLength);
            randomSerial[i] = (byte) charactors.charAt(j);
            seed = seed ^ randomNumber.nextInt();
        }
        return (new String(randomSerial));
    }
   /** 
 * @Description: 拼装加密报文
 * @param obj
 * @return
 * @throws Exception 
 * @author w_jiqing 
 */
    public String buildSignPlain(Object obj) throws Exception{
        // 去掉多一个下划线的问题
        XStream xstream = new XStream(new DomDriver("UTF-8", new NoNameCoder()));
        xstream.processAnnotations(obj.getClass());
        return xstream.toXML(obj);       
    }
    /** 
     * @Description: 将金额格式化 
     * @param num
     * @return 
     * @author w_jiqing 
     */
    private String format(BigDecimal num){
        String numString = num.toString();
        if(numString.indexOf(".") != -1){
            return StringUtils.substringBefore(numString, ".");
        }
        return numString;
    }
    
    /** 
     * @Description: 替换国付宝订单号前2位为WF
     * @param orderId
     * @return 
     * @author w_jiqing 
     */
    private static String modifyOrderId(String orderId, String chann) {
		//中信
		if ("15".equals(chann)) {
			orderId = "WF" + orderId.substring(2);
		}
		//兴业
		if ("16".equals(chann)) {
			orderId = "XY" + orderId.substring(2);
		}
		return orderId;
	}
}
